package com.sxbbc.common.basics.utils.calculation;

import java.io.*;
import java.math.BigDecimal;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.text.DecimalFormat;
import java.util.*;

import javax.servlet.http.HttpServletRequest;

import com.alibaba.fastjson.JSON;
import com.sxbbc.common.basics.https.HttpUtils;
import org.apache.commons.lang3.StringUtils;

import com.sxbbc.common.basics.enums.RandNumType;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.function.common.GetRest;
import com.function.common.RestResponse;
import com.sxbbc.common.basics.https.HttpUtil;
import com.sxbbc.common.basics.service.config.Config;
import com.sxbbc.common.basics.utils.encrypts.pwd.Encode;
import com.sxbbc.common.basics.utils.radoms.RandNumUtils;
import org.apache.http.HttpResponse;
import org.apache.http.util.EntityUtils;

/**
 * 计算方法
 *
 * @author arno
 */
public class CalcuUtils {

    private static CalcuUtils calcuUtils = null;

    public static CalcuUtils getInstance() {
        if (calcuUtils == null) {
            synchronized (CalcuUtils.class) {
                if (calcuUtils == null) {
                    calcuUtils = new CalcuUtils();
                }
            }
        }
        return calcuUtils;
    }

    private double EARTH_RADIUS = 6371.004;

    private double rad(double d) {
        return d * Math.PI / 180.0;
    }

    /**
     * 获取唯一编号
     *
     * @param a 数据来源平台 表示业务类型前缀
     * @return
     */
    public final String getOrderCode(String a) {
        String time;
        Calendar cal = Calendar.getInstance();
        int random = (int) (Math.random() * 900) + 100;
        time = "" + a + cal.get(Calendar.HOUR) + String.valueOf(random).charAt(0)
                + cal.get(Calendar.MINUTE) + String.valueOf(random).charAt(1) + cal.get(Calendar.SECOND)
                + String.valueOf(random).charAt(2) + cal.get(Calendar.MILLISECOND);
        time = time + RandNumUtils.getInstance().get(RandNumType.NUMBER, 3);
        return time;
    }

    /**
     * 加
     *
     * @param a1    加数
     * @param a2    被加数
     * @param index 保留位数
     * @return 四舍五入 保留两位小数
     */
    public BigDecimal add(BigDecimal a1, BigDecimal a2, int index) {
        return a1.add(a2).setScale(index, BigDecimal.ROUND_HALF_UP);
    }

    /**
     * 减
     *
     * @param a1    减数
     * @param a2    被减数
     * @param index 保留位数
     * @return 四舍五入 保留两位小数
     */
    public BigDecimal sub(BigDecimal a1, BigDecimal a2, int index) {
        return a1.subtract(a2).setScale(index, BigDecimal.ROUND_HALF_UP);
    }

    /**
     * 乘
     *
     * @param a1    乘数
     * @param a2    被乘数
     * @param index 保留位数
     * @return 四舍五入 保留两位小数
     */
    public BigDecimal mul(BigDecimal a1, BigDecimal a2, int index) {
        return a1.multiply(a2).setScale(index, BigDecimal.ROUND_HALF_UP);
    }

    /**
     * 除
     *
     * @param d1    除数
     * @param d2    被除数
     * @param index 保留位数
     * @return 四舍五入 保留两位小数
     */
    public BigDecimal div(BigDecimal d1, BigDecimal d2, int index) {
        if (d2.compareTo(BigDecimal.ZERO) == 0) {
            return BigDecimal.ZERO;
        }
        return d1.divide(d2, index, BigDecimal.ROUND_HALF_UP);
    }

    /**
     * 判断两个int类型的是否相等
     *
     * @param a
     * @param b
     * @return
     */
    public boolean isEquals(Integer a, Integer b) {
        if (a == null) {
            if (b.equals(a) || b == a) {
                return true;
            }
        } else {
            if (a.equals(b) || b == a) {
                return true;
            }
        }
        return false;
    }

    /**
     * 获取UUID
     *
     * @return
     */
    public String getUUid() {
        String uuid = UUID.randomUUID().toString().replaceAll("-", "").toUpperCase();
        uuid = Encode.getInstance().encode(uuid);
        return uuid;
    }

    /**
     * string[]转list<int>对象
     *
     * @param arr
     * @return
     */
    public List<Integer> getIntegerList(String[] arr) {
        List<Integer> list = new ArrayList<Integer>();
        for (String s : arr) {
            if (!StringUtils.isEmpty(s)) {
                Integer a = Integer.parseInt(s.trim());
                list.add(a);
            }
        }
        return list;
    }

    /**
     * string[]转list<int>对象 倒叙
     *
     * @param arr
     * @return
     */
    public List<Integer> getListDesc(String[] arr) {
        List<Integer> list = new ArrayList<Integer>();
        for (int i = arr.length - 1; i > -1; i--) {
            String s = arr[i];
            if (!StringUtils.isEmpty(s)) {
                Integer a = Integer.parseInt(s);
                list.add(a);
            }
        }
        return list;
    }

    public String getRemoteHost(HttpServletRequest request) {
        String ip = request.getHeader("x-forwarded-for");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return ip;
    }

    /**
     * 计算店铺评分
     *
     * @param totalScore 总分
     * @param count      有效评论数
     * @author leehao
     */
    public String calBusinessScore(BigDecimal totalScore, BigDecimal count) {
        if (totalScore == null) {
            totalScore = BigDecimal.ZERO;
        }
        //计算平均分数
        BigDecimal averageScore = null;
        try {
            averageScore = totalScore.divide(count, 2, BigDecimal.ROUND_HALF_UP);
        } catch (Exception e) {
            averageScore = BigDecimal.ZERO;
        }
        //转换 低中高
        final BigDecimal two = new BigDecimal(2);
        final BigDecimal four = new BigDecimal(4);
        if (averageScore.compareTo(BigDecimal.ZERO) > -1 && averageScore.compareTo(two) < 1) {
            // score >= 0 and score <= 2 ([0,2])
            return "低";
        } else if (averageScore.compareTo(two) == 1 && averageScore.compareTo(four) < 1) {
            // score > 2 and score <= 4 ((2,4])
            return "中";
        } else if (averageScore.compareTo(four) == 1) {
            // score > 4 ((4,..])
            return "高";
        }
        return "";
    }

    /**
     * 分红模式中，根据孵化时间段平均发放
     *
     * @param num
     * @param totalDay
     * @return 举例：孵化天数 totalDay 144天，num 共30张券 返回值:[5, 28, 4, 2] 含义： 每5天发一次券，共发28次  ，剩下4天内 发最后剩下的2张券
     */  // 30  144
    public List<Integer> calBonusAvgVal(int num, int totalDay) {

        if (totalDay > 0 && num > 0) {
            if (totalDay % num == 0) {
                return Arrays.asList(totalDay / num, num);
            } else {
                //前期每隔i天发放一张券
                int i = (totalDay / num) + 1;
                //前期每隔i天发放一张券 ,共发 s 次
                int s = totalDay / i;
                // 最后剩余t张券
                int t = num - s;
                //于此同时时间也剩下最后v天
                int v = totalDay - i * s;
                return Arrays.asList(i, s, v, t);
            }
        }
        return new ArrayList<>();
    }

    /**
     * 校验银行卡三元素
     *
     * @param realname 真实姓名
     * @param idCard   身份证
     * @param bankCard 银行卡号
     * @return
     */
    public RestResponse validBankcode3(String realname, String idCard, String bankCard) {
        String jhBankKey = Config.properties.getJhBankKey();
        String encode = null;
        try {
            encode = URLEncoder.encode(realname, "utf-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
            throw new RuntimeException("中文字符转换失败");
        }
        String url_3 = "http://v.juhe.cn/verifybankcard3/query?key=" + jhBankKey + "&realname=" + encode + "&bankcard=" + bankCard + "&idcard=" + idCard;
        String result = HttpUtil.getInstance().post(url_3, "");
        if (!StringUtils.isBlank(result)) {
            JSONObject jsonObject = JSONObject.parseObject(result);
            if (this.isEquals(0, jsonObject.getInteger("error_code"))) {
                JSONObject object = jsonObject.getJSONObject("result");
                if (this.isEquals(1, object.getInteger("res"))) {
                    return GetRest.getSuccess("银行卡认证成功");
                } else {
                    return GetRest.getFail("银行卡认证失败：" + object.getString("message"));
                }
            } else {
                return GetRest.getFail("银行卡认证失败：" + jsonObject.getString("reason"));
            }
        } else {
            return GetRest.getFail("银行卡认证失败,请联系客服");
        }
    }

    /**
     * 校验银行卡四元素 （旧版）
     *
     * @param realname 真实姓名
     * @param idCard   身份证
     * @param bankCard 银行卡号
     * @param phone    手机号
     * @return
     */
    public RestResponse validBankcode41(String realname, String idCard, String bankCard, String phone) {
        String jhBankKey = Config.properties.getJhBankKey();
        String encode = null;
        try {
            encode = URLEncoder.encode(realname, "utf-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
            throw new RuntimeException("中文字符转换失败");
        }
        String url_4 = "http://v.juhe.cn/verifybankcard4/query?key=" + jhBankKey + "&realname=" + encode + "&bankcard="
                + bankCard + "&idcard=" + idCard + "&mobile=" + phone;
        String result = HttpUtil.getInstance().post(url_4, "");
        if (!StringUtils.isBlank(result)) {
            JSONObject jsonObject = JSONObject.parseObject(result);
            if (this.isEquals(0, jsonObject.getInteger("error_code"))) {
                JSONObject object = jsonObject.getJSONObject("result");
                if (this.isEquals(1, object.getInteger("res"))) {
                    return GetRest.getSuccess("银行卡认证成功");
                } else {
                    return GetRest.getFail("银行卡认证失败：" + object.getString("message"));
                }
            } else {
                return GetRest.getFail("银行卡认证失败：" + jsonObject.getString("reason"));
            }
        } else {
            return GetRest.getFail("银行卡认证失败,请联系客服");
        }
    }

    /**
     * 校验银行卡四元素(阿里云)
     *
     * @param realname 真实姓名
     * @param idCard   身份证
     * @param bankCard 银行卡号
     * @param phone    手机号
     * @return
     */
    public RestResponse validBankcode4(String realname, String idCard, String bankCard, String phone) {
        String host = "https://tbank.market.alicloudapi.com";
        String path = "/bankCheck4New";
        String method = "GET";
        String appcode = "a06dbe7ab1824cf88bb588d42593573c";
        Map<String, String> headers = new HashMap<String, String>();
        //最后在header中的格式(中间是英文空格)为Authorization:APPCODE 83359fd73fe94948385f570e3c139105
        headers.put("Authorization", "APPCODE " + appcode);
        Map<String, String> querys = new HashMap<String, String>();
        querys.put("accountNo", bankCard);
        querys.put("idCard", idCard);
        querys.put("mobile", phone);
        querys.put("name", realname);
        //JDK 1.8示例代码请在这里下载：  http://code.fegine.com/Tools.zip

        try {
            /**
             * 重要提示如下:
             * HttpUtils请从
             * https://github.com/aliyun/api-gateway-demo-sign-java/blob/master/src/main/java/com/aliyun/api/gateway/demo/util/HttpUtils.java
             * 或者直接下载：
             * http://code.fegine.com/HttpUtils.zip
             * 下载
             *
             * 相应的依赖请参照
             * https://github.com/aliyun/api-gateway-demo-sign-java/blob/master/pom.xml
             * 相关jar包（非pom）直接下载：
             * http://code.fegine.com/aliyun-jar.zip
             */
            HttpResponse response = HttpUtils.doGet(host, path, method, headers, querys);
            //System.out.println(response.toString());如不输出json, 请打开这行代码，打印调试头部状态码。
            //状态码: 200 正常；400 URL无效；401 appCode错误； 403 次数用完； 500 API网管错误
            //获取response的body
            String result = EntityUtils.toString(response.getEntity());
            System.out.println(result);
            JSONObject jsonObject = JSON.parseObject(result);
            if (StringUtils.equals("01", jsonObject.getString("status"))) {
                return GetRest.getSuccess("银行卡认证成功",jsonObject);
            } else {
                return GetRest.getFail("银行卡认证失败：" + jsonObject.getString("msg"));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return GetRest.getSuccess("银行卡认证成功");
    }

    /**
     * 校验身份证二元素 （使用）
     *
     * @param realname
     * @param idNo
     * @return
     */
    public boolean validIdentity2(String realname, String idNo) {

        String host = "https://idenauthen.market.alicloudapi.com";
        String path = "/idenAuthentication";
        String method = "POST";
        String appcode = "a06dbe7ab1824cf88bb588d42593573c";
        Map<String, String> headers = new HashMap<String, String>();
        //最后在header中的格式(中间是英文空格)为Authorization:APPCODE 83359fd73fe94948385f570e3c139105
        headers.put("Authorization", "APPCODE " + appcode);
        //根据API的要求，定义相对应的Content-Type
        headers.put("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
        Map<String, String> querys = new HashMap<String, String>();
        Map<String, String> bodys = new HashMap<String, String>();
        bodys.put("idNo", idNo);
        bodys.put("name", realname);
        try {
            /**
             * 重要提示如下:
             * HttpUtils请从
             * https://github.com/aliyun/api-gateway-demo-sign-java/blob/master/src/main/java/com/aliyun/api/gateway/demo/util/HttpUtils.java
             * 下载
             *
             * 相应的依赖请参照
             * https://github.com/aliyun/api-gateway-demo-sign-java/blob/master/pom.xml
             */
            HttpResponse response = HttpUtils.doPost(host, path, method, headers, querys, bodys);
            //获取response的body
            String result = EntityUtils.toString(response.getEntity());
            JSONObject jsonObject = JSON.parseObject(result);
            if (StringUtils.equals("0000", jsonObject.getString("respCode"))) {
                return true;
            } else {
                return false;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

    public static void main(String[] args) {
        // System.out.println(new CalcuUtils().calBonusAvgVal(30,150));

//        Map<String, String> s = new CalcuUtils().getLatAndLonByAmap("36de73d5a16e065f5284270059e70633", "东莞");
//        System.out.println(s);
        new CalcuUtils().validIdentity2("张强", "362428199611050617");
    }

    /**
     * 生成地址json文件
     *
     * @param filePath 文件路径
     * @param addr     地址json数据
     * @author xiaoky
     */
    public void createAddrJson(String filePath, JSONArray addr) {
        String fullPath = filePath + "//json//addr" + ".json";
        // 生成json格式文件
        try {
            // 保证创建一个新文件
            File file = new File(fullPath);
            if (!file.getParentFile().exists()) {
                // 如果父目录不存在，创建父目录
                file.getParentFile().mkdirs();
            }
            if (file.exists()) {
                // 如果已存在,删除旧文件
                file.delete();
            }
            file.createNewFile();

            String jsonString = addr.toJSONString();

            // 将格式化后的字符串写入文件
            Writer write = new OutputStreamWriter(new FileOutputStream(file), "UTF-8");
            write.write(jsonString);
            write.flush();
            write.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 根据地址获取经纬度 百度地图
     *
     * @param baiduAk 百度地图ak
     * @param address 地址
     * @return java.util.Map<java.lang.String, java.lang.String>
     * @author leehao
     */
    public Map<String, String> getLatAndLon(String baiduAk, String address) {
        String url = "http://api.map.baidu.com/geocoding/v3/?output=json&ak=" + baiduAk;
        String params = "&address=" + URLEncoder.encode(address);
        String result = HttpUtil.getInstance().post(url, params);
        Map<String, String> map = new HashMap<String, String>();
        String lng = "";
        String lat = "";
        JSONObject json = JSONObject.parseObject(result);
        if (StringUtils.equals("0", String.valueOf(json.get("status")))) {
            JSONObject jsonObject = json.getJSONObject("result");
            if (jsonObject != null) {
                JSONObject localtion = jsonObject.getJSONObject("location");
                if (localtion != null) {
                    lng = localtion.getString("lng");
                    lat = localtion.getString("lat");
                }
            }
        }
        map.put("lon", lng);
        map.put("lat", lat);
        return map;
    }

    /**
     * 根据地址获取经纬度 高德地图
     *
     * @param key     高德Key
     * @param address 地址
     *                规则遵循：省份、城市、区县、城镇、乡村、街道、门牌号码、屋邨、大厦
     * @return java.util.Map<java.lang.String, java.lang.String>
     * @author leehao
     */
    public Map<String, String> getLatAndLonByAmap(String key, String address) {

        String url = "https://restapi.amap.com/v3/geocode/geo?&output=JSON&key=" + key;
        String params = "&address=" + URLEncoder.encode(address);
        String result = HttpUtil.getInstance().post(url, params);
        Map<String, String> map = new HashMap<>();
        JSONObject resultJson = JSONObject.parseObject(result);
        if (StringUtils.equals("1", String.valueOf(resultJson.get("status")))) {
            JSONArray jsonArray = resultJson.getJSONArray("geocodes");
            for (int i = 0; i < jsonArray.size(); i++) {
                JSONObject json = jsonArray.getJSONObject(i);
                String location = json.getString("location");
                String[] locationArr = location.split(",");
                map.put("lon", locationArr[0]);
                map.put("lat", locationArr[1]);
            }
        }
        return map;
    }

    /**
     * 计算两点间距离
     *
     * @param lat1 纬度1
     * @param lng1 经度1
     * @param lat2 纬度2
     * @param lng2 经度2
     * @author leehao
     */
    public double getDistance(double lat1, double lng1, double lat2, double lng2) {
        double radLat1 = rad(lat1);
        double radLat2 = rad(lat2);
        double a = radLat1 - radLat2;
        double b = rad(lng1) - rad(lng2);
        double s = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a / 2), 2) + Math.cos(radLat1) * Math.cos(radLat2) * Math.pow(Math.sin(b / 2), 2)));
        s = s * EARTH_RADIUS;
        DecimalFormat df = new DecimalFormat("######0.00");
        double f = Double.parseDouble(df.format(s));
        return f;
    }

    /**
     * 替换匿名昵称
     *
     * @param nickName
     * @return
     * @author xiaoky
     */
    public String replaceHideName(String nickName) {
        String str = "";
        if (nickName != null && nickName.length() >= 3) {
            str = nickName.substring(0, 1);
            str += "***";
            str += nickName.substring(nickName.length() - 1, nickName.length());
        } else {
            str = "*****";
        }
        return str;
    }

    /**
     * 根据类和值获取转换后的类
     *
     * @param clazz 类 如BigDecimal.class
     * @param value 值
     * @return T
     * @author leehao
     */
    @SuppressWarnings("unchecked")
    public <T> T getValueByClass(Class<T> clazz, String value) {
        Object obj = null;
        try {
            if (clazz == BigDecimal.class) {
                obj = new BigDecimal(value);
            } else if (clazz == Integer.class || clazz == int.class) {
                obj = Integer.parseInt(value);
            } else if (clazz == String.class) {
                obj = String.valueOf(value);
            } else {
                return null;
            }
        } catch (NumberFormatException e) {
            e.printStackTrace();
        }
        return (T) obj;
    }
}
